<?php
if(!interface_exists('XEventListener', false)){
	require_once(dirname(__FILE__).DIRECTORY_SEPARATOR.'XEventListener.php');
}
if(!interface_exists('XEventPublisher', false)){
	require_once(dirname(__FILE__).DIRECTORY_SEPARATOR.'XEventPublisher.php');
}
final class XEventContext implements XEventListener, XEventPublisher{
	private static $instance = null;
	private $listeners = array();
	private $eventListeners = array();
	
	private function __construct() {
	
	}
	
	/** 
	 * @return XEventContext
	 */	
	static function singleton() {
		if (!self::$instance) {
			self::$instance = new self;
		}
		return self::$instance;
	}
	
	public function addListener(XEventListener $listener){
		$this->listeners[] = $listener;
		return $this;
	}
	
	public function addListenerByEvent(XEventListener $listener, $event){
		if(!isset($this->eventListeners[$event])){
			$this->eventListeners[$event] = array();
		}
		$this->eventListeners[$event][] = $listener;
		return $this;
	}
	
	public function addListenerByParams(XEventListener $listener, $params){
		if(!isset($params['onEvent'])){
			return $this->addListener($listener);
		}
		$onEvent = $params['onEvent'];
		if(preg_match("/\w+\s*\|\s*\w+/i", $onEvent)){
			$events = preg_split("/\s*\|\s*/i", $onEvent);
			foreach($events as $event){
				$this->addListenerByEvent($listener, $event);
			}
			return $this;
		}
		return $this->addListenerByEvent($listener, $params['onEvent']);
	}
		
	public function listeners($event = null){
		if(is_null($event)){			
			return $this->listeners;
		}
		if(isset($this->eventListeners[$event])){
			return $this->eventListeners[$event];
		}
		return array();
	}
		
	public function onEvent(XEvent $event){
		$class = get_class($event);
		$loader = XClassLoader::loader($class);		
		if($class == "XTypeMatchEvent" 
			|| $loader->isSubclassOf('XTypeMatchEvent')){
			$type = $event->getType();
			$keys = array_keys($this->eventListeners);
			foreach($keys as $key){
				if(preg_match("/{$key}/i", $type) 
					&& isset($this->eventListeners[$key])){
					$this->_onEventByType($event, $key);
				}
			}
		}elseif($class == "XTypeFilterEvent" 
			|| $loader->isSubclassOf('XTypeFilterEvent')){
			$type = $event->getType();
			if(isset($this->eventListeners[$type])){
				$this->_onEventByType($event, $type);
			}
		}elseif(isset($this->eventListeners[$class])){
			$this->_onEventByType($event, $class);
		}
		foreach($this->listeners as $listener){
			$listener->onEvent($event);
		}
	}
	
	private function _onEventByType(XEvent $event, $type){
		foreach($this->eventListeners[$type] as $listener){
			$listener->onEvent($event);
		}
	}
	
	public function publish(XEvent $event){
		$this->onEvent($event);
	}
}
?>